﻿/*With thanks to http://nayyeri.net/how-to-serialize-a-mailmessage */
using System;
using System.Net.Mail;
using System.Xml;
using System.Xml.Serialization;


namespace CloudMailShared
{
    public class SerializableMailMessage : MailMessage, IXmlSerializable
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableMailMessage"/> class.
        /// </summary>
        public SerializableMailMessage() : base() { }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableMailMessage"/> class.
        /// </summary>
        /// <param name="from">A <see cref="T:System.Net.Mail.MailAddress"/> that contains the address of the sender of the e-mail message.</param>
        /// <param name="to">A <see cref="T:System.Net.Mail.MailAddress"/> that contains the address of the recipient of the e-mail message.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="from"/> is null.
        /// -or-
        /// <paramref name="to"/> is null.
        /// </exception>
        /// <exception cref="T:System.FormatException">
        /// 	<paramref name="from"/> or <paramref name="to"/> is malformed.
        /// </exception>
        public SerializableMailMessage(MailAddress from, MailAddress to) : base(from, to) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableMailMessage"/> class.
        /// </summary>
        /// <param name="from">From.</param>
        /// <param name="to">To.</param>
        public SerializableMailMessage(string from, string to) : base(from, to) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="SerializableMailMessage"/> class.
        /// </summary>
        /// <param name="from">From.</param>
        /// <param name="to">To.</param>
        /// <param name="subject">The subject.</param>
        /// <param name="body">The body.</param>
        public SerializableMailMessage(string from, string to, string subject, string body) : base(from, to, subject, body) { }

        /// <summary>
        /// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
        /// </returns>
        System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Gets the config section.
        /// </summary>
        /// <param name="xml">The XML.</param>
        /// <param name="nodePath">The node path.</param>
        /// <returns></returns>
        public XmlNode GetConfigSection(XmlDocument xml, string nodePath)
        {
            return xml.SelectSingleNode(nodePath);
        }

        /// <summary>
        /// Generates an object from its XML representation.
        /// </summary>
        /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized.</param>
        public void ReadXml(XmlReader reader)
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(reader);

            // Properties
            XmlNode rootNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage");
            this.IsBodyHtml = Convert.ToBoolean(rootNode.Attributes["IsBodyHtml"].Value);
            this.Priority = (MailPriority)Convert.ToInt16(rootNode.Attributes["Priority"].Value);

            // From
            XmlNode fromNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/From");
            string fromDisplayName = string.Empty;
            if (fromNode.Attributes["DisplayName"] != null)
                fromDisplayName = fromNode.Attributes["DisplayName"].Value;

            MailAddress fromAddress = new MailAddress(fromNode.InnerText, fromDisplayName);
            this.From = fromAddress;

            // To
            XmlNode toNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/To/Addresses");
            foreach (XmlNode node in toNode.ChildNodes)
            {
                string toDisplayName = string.Empty;

                if (node.Attributes["DisplayName"] != null)
                    toDisplayName = node.Attributes["DisplayName"].Value;

                MailAddress toAddress = new MailAddress(node.InnerText, toDisplayName);
                this.To.Add(toAddress);
            }

            // CC
            XmlNode ccNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/CC/Addresses");

            if (ccNode != null)
            {
                foreach (XmlNode node in ccNode.ChildNodes)
                {
                    string ccDisplayName = string.Empty;

                    if (node.Attributes["DisplayName"] != null)
                        ccDisplayName = node.Attributes["DisplayName"].Value;

                    MailAddress ccAddress = new MailAddress(node.InnerText, ccDisplayName);
                    this.CC.Add(ccAddress);
                }
            }

            // Bcc
            XmlNode bccNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Bcc/Addresses");

            if (bccNode != null)
            {
                foreach (XmlNode node in bccNode.ChildNodes)
                {
                    string bccDisplayName = string.Empty;

                    if (node.Attributes["DisplayName"] != null)
                        bccDisplayName = node.Attributes["DisplayName"].Value;

                    MailAddress bccAddress = new MailAddress(node.InnerText, bccDisplayName);
                    this.Bcc.Add(bccAddress);
                }
            }

            // Subject
            XmlNode subjectNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Subject");
            this.Subject = subjectNode.InnerText;

            // Body
            XmlNode bodyNode = GetConfigSection(xml, "SerializableMailMessage/MailMessage/Body");
            this.Body = bodyNode.InnerText;
        }


        /// <summary>
        /// Converts an object into its XML representation.
        /// </summary>
        /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized.</param>
        public void WriteXml(XmlWriter writer)
        {
            if (this != null)
            {
                writer.WriteStartElement("MailMessage");
                writer.WriteAttributeString("Priority", Convert.ToInt16(this.Priority).ToString());
                writer.WriteAttributeString("IsBodyHtml", this.IsBodyHtml.ToString());

                // From
                writer.WriteStartElement("From");
                if (!string.IsNullOrEmpty(this.From.DisplayName))
                    writer.WriteAttributeString("DisplayName", this.From.DisplayName);

                writer.WriteRaw(this.From.Address);
                writer.WriteEndElement();

                // To
                writer.WriteStartElement("To");
                writer.WriteStartElement("Addresses");

                foreach (MailAddress address in this.To)
                {
                    writer.WriteStartElement("Address");
                    if (!string.IsNullOrEmpty(address.DisplayName))
                        writer.WriteAttributeString("DisplayName", address.DisplayName);

                    writer.WriteRaw(address.Address);
                    writer.WriteEndElement();
                }

                writer.WriteEndElement();
                writer.WriteEndElement();

                // CC
                if (this.CC.Count > 0)
                {
                    writer.WriteStartElement("CC");
                    writer.WriteStartElement("Addresses");

                    foreach (MailAddress address in this.CC)
                    {
                        writer.WriteStartElement("Address");

                        if (!string.IsNullOrEmpty(address.DisplayName))
                            writer.WriteAttributeString("DisplayName", address.DisplayName);

                        writer.WriteRaw(address.Address);
                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                    writer.WriteEndElement();
                }

                // Bcc
                if (this.Bcc.Count > 0)
                {
                    writer.WriteStartElement("Bcc");
                    writer.WriteStartElement("Addresses");

                    foreach (MailAddress address in this.Bcc)
                    {
                        writer.WriteStartElement("Address");

                        if (!string.IsNullOrEmpty(address.DisplayName))
                            writer.WriteAttributeString("DisplayName", address.DisplayName);

                        writer.WriteRaw(address.Address);
                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                    writer.WriteEndElement();
                }

                // Subject
                writer.WriteStartElement("Subject");
                writer.WriteRaw(this.Subject);
                writer.WriteEndElement();

                // Body
                writer.WriteStartElement("Body");
                writer.WriteCData(Body);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
    }
}